
(in-package :xlui)

(defclass nehe-view (agent-3d-view)
  ((gl-version :reader gl-version)
   (vendor :reader gl-vendor)
   (renderer :reader gl-renderer)
   (extensions :reader gl-extensions)
   (max-texture-units :reader max-texture-units :initform 0)
   (multi-texture-p :accessor multi-texture-p :initform nil)
   (supports-vbuffers-p :accessor supports-vbuffers-p :initform nil)))

(defmethod init :around ((self nehe-view))
  ""
  (with-slots (gl-version vendor renderer extensions supports-vbuffers-p) self
    (setf gl-version (ccl:%get-cstring (glGetString GL_VERSION)))
    (setf extensions (cl-ppcre:split "\\s+" (ccl:%get-cstring (glGetString GL_EXTENSIONS))))
    (setf vendor (ccl:%get-cstring (glGetString GL_VENDOR)))
    (setf renderer (ccl:%get-cstring (glGetString GL_RENDERER)))
    (setf supports-vbuffers-p (has-extension self "GL_ARB_vertex_buffer_object"))

    (call-next-method)

    (when (multi-texture-p self)
      (init-multitexturing self))))

(defmethod use-multi-texture ((view nehe-view) texture-name &key mag-filter min-filter)
  "This depends on the texture-arb class defined in gllib."
  (let ((texture (gethash texture-name (textures view))))
    ;; load texture from file if necessary
    (unless texture
      (setq texture (make-instance 'texture-arb
                      :source (texture-file view texture-name) :glview view
                      :mag-filer mag-filter :min-filter min-filter))
      (setf (gethash texture-name (textures view)) texture))
    ;; make the texture active (for now assume a 2D texture)
    (when Texture
      (glBindTexture GL_TEXTURE_RECTANGLE_ARB (binding texture))
      texture)))

(defmethod has-extension ((self nehe-view) ext-name)
  "Check if view has OpenGL extension.  Only works when there is an active GL context, otherwise
it will crash the program."
  (find ext-name (gl-extensions self) :test #'string=))

(defmethod init-multitexturing ((view nehe-view))
  ;; 
  (when (and (has-extension view "GL_ARB_multitexture")
             (has-extension view "GL_ARB_texture_env_combine"))
    ;; In NeHe there are several calls to wglGetProcAddreess (a windows function)
    ;; to load function pointers for the multi-texturing extensions, but since it
    ;; appears that multitextures are now part of the standard, i.e. glMultiTexCoord1fARB
    ;; is defined, all we do here is set the enable bit and determine the maximum number
    ;; of textures this card can support.
    (setf (multi-texture-p view) t)
    (ccl:rlet ((max-texels #>GLint))
      (glGetIntegerv GL_MAX_TEXTURE_UNITS max-texels)
      (setf (slot-value view 'max-texture-units) max-texels))))


(defparameter *ambient* {0.2 0.2 0.2})
(defparameter *diffuse* {1.0 1.0 1.0})
(defparameter *position* {0.0 0.0 2.0})

(defmethod enable-lights ((view nehe-view))
  (glLightfv GL_LIGHT1 GL_AMBIENT *ambient*)
  (glLightfv GL_LIGHT1 GL_DIFFUSE *diffuse*)
  (glLightfv GL_LIGHT1 GL_POSITION *position*)
  (glEnable GL_LIGHT1))


(defun test-nehe-view ()
  (slui (:application-window :title "Testing" :margin "0"
         (:nehe-view :name "Nehe"))))